﻿using HardcoreGame.Content.NPCs.Enemies.Events.FrostLegion;
using Mono.Cecil.Cil;
using MonoMod.Cil;
using System;
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;

namespace HardcoreGame.Common.Systems
{
    public class FrostLegionSystem : ModSystem
    {
        public override void Load()
        {
            IL_Main.StartInvasion += delegate (ILContext il)
            {
                ILCursor c;
                ILCursor ilcursor = c = new ILCursor(il);
                Func<Instruction, bool>[] array = [(i) => i.MatchLdcI4(80), (i) => i.MatchLdcI4(40)];
                if (ilcursor.TryGotoNext(array))
                {
                    ILCursor cc;
                    ILCursor ilcursor2 = cc = c.Clone();
                    Func<Instruction, bool>[] array2 = [(i) => i.MatchStsfld(typeof(Main), "invasionSize")];
                    if (ilcursor2.TryGotoNext(array2))
                    {
                        c.Emit(OpCodes.Ldarg_0);
                        c.Emit(OpCodes.Ldc_I4_2);
                        ILLabel skip = c.DefineLabel();
                        c.Emit(OpCodes.Bne_Un, skip);
                        c.Emit(OpCodes.Ldc_I4, 150);
                        c.Emit(OpCodes.Ldc_I4, 120);
                        c.Emit(OpCodes.Ldloc_0);
                        c.Emit(OpCodes.Mul);
                        c.Emit(OpCodes.Add);
                        ILLabel label = c.DefineLabel();
                        c.Emit(OpCodes.Br, label);
                        c.MarkLabel(skip);
                        cc.MarkLabel(label);
                        return;
                    }
                }
            };
            IL_NPC.checkDead += delegate (ILContext il)
            {
                ILCursor c2;
                ILCursor ilcursor3 = c2 = new ILCursor(il);
                MoveType moveType = (MoveType)2;
                Func<Instruction, bool>[] array3 = [(i) => i.MatchCall(typeof(NPC), "GetNPCInvasionGroup")];
                if (ilcursor3.TryGotoNext(moveType, array3))
                {
                    ILCursor cc2;
                    ILCursor ilcursor4 = cc2 = c2.Clone();
                    MoveType moveType2 = (MoveType)2;
                    Func<Instruction, bool>[] array4 =
                    [
                        (i) => i.MatchLdsfld(typeof(Main), "invasionSize"),
                        delegate (Instruction i)
                        {
                            return i.MatchLdloc(out int num);
                        },
                    ];
                    if (ilcursor4.TryGotoNext(moveType2, array4))
                    {
                        c2.Emit(OpCodes.Ldarg_0);
                        c2.Emit(OpCodes.Call, typeof(FrostLegionSystem).GetMethod("GetInvasionGroup"));
                        cc2.Emit(OpCodes.Ldarg_0);
                        cc2.Emit(OpCodes.Call, typeof(FrostLegionSystem).GetMethod("OnKillInvader"));
                        return;
                    }
                }
            };
        }
        public static int GetInvasionGroup(int vanillaPick, NPC npc)
        {
            if (npc.type != ModContent.NPCType<SnowmanTank>())
            {
                return vanillaPick;
            }
            if (npc.ai[1] >= 1f)
            {
                return 0;
            }
            return 2;
        }
        public static void SpawnFrostLegionNPC(int x, int y, Player player)
        {
            int angels = 0;
            int men = 0;
            for (int i = 0; i < 200; i++)
            {
                NPC npc = Main.npc[i];
                if (npc.active)
                {
                    if (npc.type == ModContent.NPCType<SnowmanTank>())
                    {
                        if (!Main.expertMode || npc.ai[1] >= 600f)
                        {
                            men += 3;
                            angels++;
                        }
                    }
                    else if (npc.type == ModContent.NPCType<SnowmanTank>())
                    {
                        angels++;
                    }
                    else if (npc.type == NPCID.SnowmanGangsta ||
                        npc.type == NPCID.MisterStabby ||
                        npc.type == NPCID.SnowBalla ||
                        npc.type == ModContent.NPCType<ExplodingSnowman>() ||
                        npc.type == ModContent.NPCType<AssaultSnowman>() ||
                        npc.type == ModContent.NPCType<SnowmanHelicopter>() ||
                        npc.type == ModContent.NPCType<SnowmanGangsta>() ||
                        npc.type == ModContent.NPCType<RPGSnowman>())
                    {
                        men++;
                    }
                }
            }
            if (angels < men / 3)
            {
                NPC.NewNPC(Entity.GetSource_NaturalSpawn(), x * 16 + 8, y * 16, ModContent.NPCType<SnowmanTank>(), 0, 0f, 0f, 0f, 0f, 255);
                return;
            }
            if (men < 9)
            {
                switch (Main.rand.Next(9))
                {
                    case 0:
                        NPC.NewNPC(Entity.GetSource_NaturalSpawn(), x * 16 + 8, y * 16, 143, 0, 0f, 0f, 0f, 0f, 255);
                        return;
                    case 1:
                        NPC.NewNPC(Entity.GetSource_NaturalSpawn(), x * 16 + 8, y * 16, 144, 0, 0f, 0f, 0f, 0f, 255);
                        return;
                    case 2:
                        NPC.NewNPC(Entity.GetSource_NaturalSpawn(), x * 16 + 8, y * 16, 145, 0, 0f, 0f, 0f, 0f, 255);
                        return;
                    case 3:
                        NPC.NewNPC(Entity.GetSource_NaturalSpawn(), x * 16 + 8, y * 16, ModContent.NPCType<ExplodingSnowman>(), 0, 0f, 0f, 0f, 0f, 255);
                        return;
                    case 4:
                        NPC.NewNPC(Entity.GetSource_NaturalSpawn(), x * 16 + 8, y * 16, ModContent.NPCType<AssaultSnowman>(), 0, 0f, 0f, 0f, 0f, 255);
                        return;
                    case 5:
                        NPC.NewNPC(Entity.GetSource_NaturalSpawn(), x * 16 + 8, y * 16, ModContent.NPCType<SnowmanHelicopter>(), 0, 0f, 0f, 0f, 0f, 255);
                        return;
                    case 6:
                        NPC.NewNPC(Entity.GetSource_NaturalSpawn(), x * 16 + 8, y * 16, ModContent.NPCType<SnowmanGangsta>(), 0, 0f, 0f, 0f, 0f, 255);
                        return;
                    case 7:
                        NPC.NewNPC(Entity.GetSource_NaturalSpawn(), x * 16 + 8, y * 16, ModContent.NPCType<SnowmanTank>(), 0, 0f, 0f, 0f, 0f, 255);
                        return;
                    case 8:
                        NPC.NewNPC(Entity.GetSource_NaturalSpawn(), x * 16 + 8, y * 16, ModContent.NPCType<RPGSnowman>(), 0, 0f, 0f, 0f, 0f, 255);
                        break;
                    default:
                        return;
                }
            }
        }
        public static int OnKillInvader(int vanillaCount, NPC npc)
        {
            if (Main.invasionType == 2)
            {
                if (npc.type == ModContent.NPCType<SnowmanTank>())
                {
                    return Main.invasionSizeStart;
                }
                if (Main.invasionSize > 1 && Main.invasionSize - vanillaCount <= 1)
                {
                    NPC.NewNPC(npc.GetSource_Death(null), (int)npc.Center.X, (int)npc.position.Y - 250, ModContent.NPCType<SnowmanTank>(), 0, 0f, 0f, 0f, 0f, 255);
                }
                if (Main.invasionSize > 0)
                {
                    return Math.Min(vanillaCount, Main.invasionSize - 1);
                }
            }
            return vanillaCount;
        }
        public override void OnWorldLoad()
        {
            if (Main.invasionType == 2 && Main.invasionSize <= 1)
            {
                Main.invasionType = 0;
                Main.invasionSize = 0;
                Main.invasionDelay = 0;
            }
        }
        public override void PreUpdateInvasions()
        {
            if (Main.invasionType == 2)
            {
                bool active = false;
                bool allDead = true;
                for (int i = 0; i < 255; i++)
                {
                    if (Main.player[i].active)
                    {
                        active = true;
                        if (!Main.player[i].dead)
                        {
                            allDead = false;
                            break;
                        }
                    }
                }
                if (active && allDead)
                {
                    Main.invasionType = 0;
                    Main.invasionSize = 0;
                    Main.invasionDelay = 0;
                    return;
                }
            }
        }
    }
}
